/*******************************************************************************
* CSCI321 Major Project 2010 - University of Wollongong                        *
********************************************************************************
* Program:		WeaveEdit                                              *
* Authors:		Simon Allen (Student#: 3457527, Unix: sa655)           *
*			Scott Bellis (Student#: 3479110, Unix: sjb900)         *
*			Jason Benger (Student#: 3454137, Unix: jb960)          *
*			Timothy Newmarch (Student#: 3459263 Unix: tgn336)      *
*			Benjamin Richardson (Student# 3467752, Unix: bjr401)   *
* Supervisor:		Daniel F. Saffioti                                     *
* Modified:		28/10/2010                                             *
* Description:		WeaveEdit is a highly portable collaborative text      *
*			editor and word processor, allowing several users to   *
*			read and edit multiple documents at the same time.     *
*			It is available for Mac OS X, Windows and Linux,       *
*			utilising Nokia's Qt development framework.            *
*******************************************************************************/


#include <QtEndian>
#include <QSocketNotifier>
#include <QHostInfo>
#include "bonjourresolver.h"

BonjourResolver::BonjourResolver(QObject *parent) : QObject(parent)
{
	serviceRef = NULL;
}

BonjourResolver::~BonjourResolver()
{
	if (serviceRef)
		DNSServiceRefDeallocate(serviceRef);
}

void BonjourResolver::resolveService(quint32 index, QString name, QString type, QString domain)
{
	if (serviceRef)
		return;

	//start resolving with the daemon
	DNSServiceErrorType error;
	error = DNSServiceResolve(&serviceRef, 0, index, name.toAscii().constData(), type.toAscii().constData(),
							  domain.toAscii().constData(), resolveCallback, this);

	if (error != kDNSServiceErr_NoError)
	{
		emit bonjourError();
		return;
	}

	//get the socket descriptor and wait for replies
	int sock = DNSServiceRefSockFD(serviceRef);

	if (sock == -1)
	{
		emit bonjourError();
		return;
	}

	//monitor the socket for new info
	QSocketNotifier *notify = new QSocketNotifier(sock, QSocketNotifier::Read, this);
	connect(notify, SIGNAL(activated(int)), this, SLOT(receiveSomeInfo(int)));
}

void BonjourResolver::receiveSomeInfo(int)
{
	DNSServiceProcessResult(serviceRef);	//calls the callback
}

void BonjourResolver::resolveCallback(DNSServiceRef ref, DNSServiceFlags flags, quint32 index, DNSServiceErrorType error,
									  const char* fullDomain, const char* host, quint16 port, quint16 txtLen, const unsigned char *txtData, void *context)
{
	if (error != kDNSServiceErr_NoError)
	{
		emit ((BonjourResolver*)context)->bonjourError();
		return;
	}

	port = qFromBigEndian(port);

	QString hostString(host);

	//remove the trailing dot that screws up Qt if needed
	if (hostString.at(hostString.length()-1) == '.')
		hostString.remove(hostString.length()-1, 1);

	QHostInfo info = QHostInfo::fromName(hostString);

	//if the address from bonjour could not be resolved to an ip
	if (info.addresses().isEmpty())
	{
		emit ((BonjourResolver*)context)->bonjourError();
		return;
	}

	QHostAddress theHost = info.addresses().first();	//send the first address if we can't find an ip4 addy

	//search for a nice ip4 address
	foreach(QHostAddress addy, info.addresses())
	{
		if (addy.protocol() == QAbstractSocket::IPv4Protocol)
		{
			theHost = addy;
			break;		//the loop, not bonjour
		}
	}

	//we have succeeded, alert someone with the data
	emit ((BonjourResolver*)context)->resolvedInfo(theHost.toString().toAscii().constData(), port);
}
